//
//  AirSocketConnect.h
//  AirCpp
//
//  Created by Penghao on 14-2-11.
//  Copyright (c) 2014年 PengHao.

//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//  http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.

#ifndef AirCpp_AirSocketConnect_h
#define AirCpp_AirSocketConnect_h

#include "../AirString/AirStringUtility.h"
#include "../AirObject/AirObject.h"
#include "../AirThread/AirThread.h"
#include "AirIO.h"
#include <string.h>
#include <stdlib.h>
#include <pthread.h>

namespace AirCpp {
    template <class CallBackClass>
    class AirSocketConnect : public AirObject{
#ifdef OSLinux
        typedef AirBSDSocketIO<AirSocketConnect> AirOSSocketIO;
#elif defined OSWindows
#endif
        
    private:
        bool is_active;
        AirThread<AirSocketConnect> *reseive_thread;

    protected:
        AirOSSocketIO *socketIO;
        CallBackClass *callback;
        AirDataStreamBuffer* read_data_buffer;
        AirData *reading_data;

        void *reseive(void *){
            read_data(0);
            return NULL;
        }
        
        void start_reseive_with_muilthread(){
            AirOperation<AirSocketConnect> *operation = new AirOperation<AirSocketConnect>();
            operation->init(this, &AirSocketConnect::reseive, NULL);
            if (reseive_thread == NULL) {
                reseive_thread = new AirThread<AirSocketConnect>();
                reseive_thread->init();
            }
            reseive_thread->run_operation(operation);
            release(operation);
        }
        
    public:
        AirSocketConnect(){
            read_data_buffer = AirDataStreamBuffer::create_outstream_buffer();
            reading_data = NULL;
            reseive_thread = NULL;
        }
        
        ~AirSocketConnect(){
            release(read_data_buffer);
            release(reading_data);
            if (reseive_thread!=NULL) {
                reseive_thread->cancel();
                release(reseive_thread);
            }
        }
        
        int init(int *_socket_handle, CallBackClass *callback_class){
            socketIO = new AirOSSocketIO(this);
            socketIO->link_to_handle(*_socket_handle, this);
            if (*_socket_handle<0) {
                delete socketIO;
                socketIO = NULL;
                return -1;
            }else{
                callback = callback_class;
            }
            return 0;
        }
        
        int init(AirString *http_hostname, unsigned int port, CallBackClass *callback_class){
            socketIO = new AirOSSocketIO(this);
            if (socketIO->init(AF_INET, SOCK_STREAM, 0)>=0) {
                if (socketIO->connect_to_host(http_hostname, port, this)>=0) {
                    callback = callback_class;
                    start_reseive_with_muilthread();
                    return 0;
                }
            }
            delete socketIO;
            socketIO = NULL;
            return -1;
        };
        
        void send_data(AirDataStreamBuffer *data){
            socketIO->write_data(data->get_c_data(), data->length());
        }
        
        void active(){
            is_active = true;
            socketIO->reseive();
        }
        
        void read_data(int i){
            AirSize_t read_size = socketIO->read_data(read_data_buffer->p_current, read_data_buffer->get_unrecived_size());
            read_data_buffer->filled_size(read_size);
            
            if (read_data_buffer->is_get_full_data()) {
                callback->received_package(this, read_data_buffer);
                read_data_buffer->clear();
            }
        }
        
        void close(){
            is_active = false;
            socketIO->close_connect();
        }
        
        //call back
        
        void connected(AirSocket<AirSocketConnect> *socket, bool *b_successed){
            callback->connected(this, b_successed);
        }

        // |head|data|
        void received_buffer(AirSocket<AirSocketConnect> *socket, AirString *data_copy){
            //开头包
            if (read_data_buffer == NULL) {
                read_data_buffer = AirDataStreamBuffer::create_outstream_buffer();
                
            }
            printf("%s", data_copy->c_str);
            release(data_copy);
        };
        
        void received_buffer_finished(AirSocket<AirSocketConnect> *socket){
            callback->received_buffer_finished(this);
        }
        
        void sentdata(AirSocket<AirSocketConnect> *socket, bool *b_successed){
            if (NULL != callback) {
                
            }
        }
        
        void recevie_time_out(AirSocket<AirSocketConnect> *socket){
            callback->recevie_time_out(this);
        };

    };
}

#endif
